#pragma once
#include <iostream>
#include <string>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstring>
#include <cerrno>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SIZE 4096
#define creater 1
#define user 2
const int proj_id = 0x66;
const std::string path = "/home/fkg/shm";
class Shm
{
private:
    key_t GetCommKey(const std::string &path, int id)
    {
        key_t key = ftok(path.c_str(), id);
        if (key < 0)
            perror("ftok");
        return key;
    };
    int Getshm(key_t key, size_t size, int flag)
    {
        int shmid = shmget(key, size, flag);
        if (shmid < 0)
            perror("shmget:");
        return shmid;
    };
    void *Attouch()
    {
        void *shmaddr = shmat(_shmid, nullptr, 0);
        if (shmaddr == nullptr)
            return nullptr;
        std::cout << "Attouch Done...  Using is: " << ToString() << std::endl;
        return shmaddr;
    };
    void DetouchShm()
    {
        shmdt(_addrshm);
        std::cout << "Delete Attouch Done..." << std::endl;
    };
    void Zero()
    {
        memset(_addrshm, 0, SIZE);
    };
public:
    Shm(const std::string &path, int proj_id, int who)
        : _path(path), _proj_id(proj_id), _who(who), _addrshm(nullptr)
    {
        _key = GetCommKey(_path, _proj_id);
        if (_who == creater)
            GetShmForCreater();
        else if (_who == user)
            GetShmForUser();
        _addrshm = Attouch();
        Zero();
        std::cout << "shmid: " << _shmid << std::endl;
        std::cout << "Key: " << ToHex() << std::endl;
    };
    std::string ToHex()
    {
        char buffer[128];
        snprintf(buffer, sizeof(buffer), "0x%0x", _key);
        return buffer;
    };
    bool GetShmForCreater()
    {
        if (_who == creater)
        {
            _shmid = Getshm(_key, SIZE, IPC_CREAT | IPC_EXCL | 0666);
            if (_shmid >= 0)
                return true;
            return false;
        }
        else
            return false;
    };
    bool GetShmForUser()
    {
        if (_who == user)
        {
            _shmid = Getshm(_key, SIZE, IPC_CREAT | 0666);
            if (_shmid >= 0)
                return true;
            return false;
        }
        else
            return false;
    };
    const std::string ToString()
    {
        if (_who == creater)
            return "creater";
        else if (_who == user)
            return "user";
        else
            return "None";
    };
    void *GetAddr()
    {
        return _addrshm;
    };
    ~Shm()
    {
        if (_addrshm != nullptr)
            DetouchShm();
        if (_who == creater)
        {
            int id = shmctl(_shmid, IPC_RMID, nullptr);
            if (id == 0)
                std::cout << "Delete success!" << std::endl;
        }
    };
private:
    int _shmid;
    key_t _key;
    std::string _path;
    int _proj_id;
    int _who;
    void *_addrshm;
};